package com.itdct.onflow.core.mp

import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper
import com.baomidou.mybatisplus.core.toolkit.PluginUtils
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor
import com.itdct.onflow.core.entity.BaseEntity
import com.itdct.onflow.core.extend.logDebug
import com.itdct.onflow.core.extend.logInfo
import net.sf.jsqlparser.JSQLParserException
import net.sf.jsqlparser.expression.*
import net.sf.jsqlparser.expression.operators.conditional.AndExpression
import net.sf.jsqlparser.expression.operators.relational.EqualsTo
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression
import net.sf.jsqlparser.expression.operators.relational.InExpression
import net.sf.jsqlparser.parser.CCJSqlParserUtil
import net.sf.jsqlparser.schema.Column
import net.sf.jsqlparser.schema.Table
import net.sf.jsqlparser.statement.Statement
import net.sf.jsqlparser.statement.select.*
import org.apache.commons.lang3.StringUtils
import org.apache.ibatis.executor.Executor
import org.apache.ibatis.mapping.BoundSql
import org.apache.ibatis.mapping.MappedStatement
import org.apache.ibatis.session.ResultHandler
import org.apache.ibatis.session.RowBounds
import java.lang.reflect.ParameterizedType
import java.sql.SQLException

/**
 * @author DCT
 * @version 1.0
 * @date 2023/11/9 23:10:18
 * @description
 */
class DeleteMpInterceptor(var deleteFieldName: String) : InnerInterceptor {
    /**
     * mapper是否需要自动添加逻辑删除
     */
    private val mapperIdNeedDelMap = HashMap<String, Boolean>()

    @Throws(SQLException::class)
    override fun beforeQuery(executor: Executor?, ms: MappedStatement, parameter: Any?, rowBounds: RowBounds?, resultHandler: ResultHandler<*>?, boundSql: BoundSql?) {
        if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.id, LOGIC_DELETE)) {
            return
        }

        if (StringUtils.isBlank(deleteFieldName)) {
            // INFO: Zhouwx: 2023/11/20 没有设置逻辑删除的字段名，也忽略添加逻辑删除
            return
        }

        val needDel = mapperIdNeedDelMap.get(ms.id)
        if (needDel == null) {
            val entityClass = findEntityClass(ms)
            if (entityClass == null || !BaseEntity::class.java.isAssignableFrom(entityClass)) {
                // INFO: Zhouwx: 2025/2/20 不是BaseEntity类型不用增加逻辑删除
                mapperIdNeedDelMap.put(ms.getId(), false)
                return
            } else {
                mapperIdNeedDelMap.put(ms.getId(), true)
            }
        } else {
            if (!needDel) {
                return
            }
        }

        val mpBs = PluginUtils.mpBoundSql(boundSql)
        val sql = mpBs.sql()
        var statement: Statement
        try {
            statement = CCJSqlParserUtil.parse(sql)
        } catch (e: JSQLParserException) {
            throw RuntimeException(e)
        }

        if (statement !is Select) {
            return
        }

        val id = ms.getId()
        val lastIndexOf = id.lastIndexOf(".")
        val functionName = id.substring(lastIndexOf + 1)
        if (excludeFunctions.contains(functionName)) {
            // INFO: DCT: 2023/11/12 QueryWrapper的查询，本来就会加逻辑删除，不需要再加了
            return
        }

        val select = statement
        val selectBody = select.getSelectBody()

        // INFO: DCT: 2023/11/12 处理核心业务
        handleSelectBody(selectBody)

        // INFO: DCT: 2023/11/12 将处理完的数据重新转为MPBoundSql
        val sqlChange: String? = statement.toString()
        mpBs.sql(sqlChange)
    }

    private fun findEntityClass(ms: MappedStatement): Class<*>? {
        val id = ms.id

        val index = id.lastIndexOf(".")
        val className = id.substring(0, index)
        if (excludeClass.contains(className)) {
            return null
        }
        try {
            val mapperClass = Class.forName(className)
            val genericInterfaces = mapperClass.getGenericInterfaces()
            for (genericInterface in genericInterfaces) {
                if (genericInterface is ParameterizedType) {
                    val actualTypeArguments = genericInterface.getActualTypeArguments()
                    if (actualTypeArguments.size > 0) {
                        val actualTypeArgument = actualTypeArguments[0]
                        if (actualTypeArgument is Class<*>) {
                            val entityClass = actualTypeArgument
                            return entityClass
                        }
                    }
                }
            }
        } catch (e: ClassNotFoundException) {
            throw RuntimeException(e)
        }

        return null
    }

    protected fun handleSelectBody(selectBody: Select?) {
        if (selectBody is PlainSelect) {
            val plainSelect = selectBody

            // INFO: DCT: 2023/11/12 处理join中的内容
            handleJoins(plainSelect)

            val where = plainSelect.getWhere()

            val fromItem = plainSelect.getFromItem()
            val equalsTo = getEqualTo(fromItem)

            if (where == null) {
                // INFO: DCT: 2023/11/12 where条件为空，增加一个where，且赋值为 表名.del = 0
                plainSelect.setWhere(equalsTo)
            } else {
                // INFO: DCT: 2023/11/12 普通where，后面直接加上本表的 表名.del = 0
                val andExpression = AndExpression(where, equalsTo)
                plainSelect.setWhere(andExpression)

                // INFO: DCT: 2023/11/12 有子查询的处理子查询
                handleWhereSubSelect(where)
            }
        }
    }

    /**
     * 这一段来自MybatisPlus的租户插件源码，通过递归的方式加上需要的SQL
     *
     * @param where
     */
    protected fun handleWhereSubSelect(where: Expression?) {
        if (where == null) {
            return
        }
        if (where is FromItem) {
            processOtherFromItem(where as FromItem)
            return
        }
        if (where.toString().indexOf("SELECT") > 0) {
            // 有子查询
            if (where is BinaryExpression) {
                // 比较符号 , and , or , 等等
                val expression = where
                handleWhereSubSelect(expression.getLeftExpression())
                handleWhereSubSelect(expression.getRightExpression())
            } else if (where is InExpression) {
                // in
                val expression = where
                val inExpression = expression.getRightExpression()
                if (inExpression is Select) {
                    handleSelectBody(inExpression.getSelectBody())
                }
            } else if (where is ExistsExpression) {
                // exists
                val expression = where
                handleWhereSubSelect(expression.getRightExpression())
            } else if (where is NotExpression) {
                // not exists
                val expression = where
                handleWhereSubSelect(expression.getExpression())
            } else if (where is Parenthesis) {
                val expression = where
                handleWhereSubSelect(expression.getExpression())
            }
        }
    }

    /**
     * 处理子查询等
     */
    protected fun processOtherFromItem(fromItem: FromItem?) {
        // 去除括号
//        while (fromItem instanceof ParenthesisFromItem) {
//            fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
//        }
        if (fromItem is ParenthesedSelect) {
            val subSelect = fromItem as Select
            handleSelectBody(subSelect)
        } else if (fromItem is ParenthesedFromItem) {
            logInfo("Perform a subQuery, if you do not give us feedback")
        }

        //        if (fromItem instanceof SubSelect) {
//            SubSelect subSelect = (SubSelect) fromItem;
//            if (subSelect.getSelectBody() != null) {
//                // INFO: Zhouwx: 2023/11/20 递归从select开始查找
//                handleSelectBody(subSelect.getSelectBody());
//            }
//        } else if (fromItem instanceof ValuesList) {
//            log.debug("Perform a subQuery, if you do not give us feedback");
//        } else if (fromItem instanceof LateralSubSelect) {
//            LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
//            if (lateralSubSelect.getSubSelect() != null) {
//                SubSelect subSelect = lateralSubSelect.getSubSelect();
//                if (subSelect.getSelectBody() != null) {
//                    // INFO: Zhouwx: 2023/11/20 递归从select开始查找
//                    handleSelectBody(subSelect.getSelectBody());
//                }
//            }
//        }
    }

    protected fun handleJoins(plainSelect: PlainSelect) {
        val joins = plainSelect.getJoins()
        if (joins == null) {
            return
        }

        for (join in joins) {
            // INFO: DCT: 2023/11/12 获取表别名，并获取 表.del = 0
            val rightItem = join.getRightItem()
            val equalsTo = getEqualTo(rightItem)

            // INFO: DCT: 2023/11/12 获取on右边的表达式
            val onExpression = join.getOnExpression()
            // INFO: DCT: 2023/11/12 给表达式增加 and 表.del = 0
            val andExpression = AndExpression(onExpression, equalsTo)

            val expressions = ArrayList<Expression?>()
            expressions.add(andExpression)
            // INFO: DCT: 2023/11/12 目前的这个表达式就是and后的表达式了，不用再增加原来的表达式，因为这个and表达式已经包含了原表达式所有的内容了
            join.setOnExpressions(expressions)
        }
    }

    protected fun getEqualTo(fromItem: FromItem): EqualsTo {
        val alias = fromItem.getAlias()

        var aliasName: String? = ""
        if (alias == null) {
            if (fromItem is Table) {
                val table = fromItem
                aliasName = table.getName()
            }
        } else {
            aliasName = alias.getName()
        }

        val equalsTo = EqualsTo()
        val leftColumn = Column()
        leftColumn.setColumnName(aliasName + "." + deleteFieldName)
        equalsTo.setLeftExpression(leftColumn)
        equalsTo.setRightExpression(LongValue(0))

        return equalsTo
    }

    companion object {
        const val LOGIC_DELETE: String = "LOGIC_DELETE"

        /**
         * 排除哪些方法不需要逻辑删除
         */
        val excludeFunctions: HashSet<String?> = HashSet<String?>()

        /**
         * 排除哪些类不需要逻辑删除
         */
        val excludeClass: HashSet<String?> = HashSet<String?>()

        init {
            excludeFunctions.add("selectList")
            excludeFunctions.add("selectById")
            excludeFunctions.add("selectBatchIds")
            excludeFunctions.add("selectByMap")
            excludeFunctions.add("selectOne")
            excludeFunctions.add("selectCount")
            excludeFunctions.add("selectObjs")
            excludeFunctions.add("selectPage")
            excludeFunctions.add("selectMapsPage")

            excludeClass.add("com.baomidou.mybatisplus.core.mapper.SqlRunner")
        }
    }
}
